package com.uvstu.common.pay.client;

import cn.uvtool.utils.HttpUtil;
import com.github.wxpay.sdk.WXPayConstants;
import com.github.wxpay.sdk.WXPayUtil;
import com.uvstu.common.pay.config.WxPayConfig;
import com.uvstu.common.pay.exception.TClientException;
import com.uvstu.common.pay.utils.StringUtil;
import com.uvstu.common.pay.utils.WxHttpUtil;
import org.apache.commons.codec.digest.DigestUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.security.Security;
import java.util.Base64;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * @version V1.0
 * @Title: 微信功能集成
 * @author: zhengweibin
 * @Description:
 * @create: 2022-12-23 11:50
 */
public class WxPayClient {

    /**
     * 初始化配置
     *
     * @param appid           应用ID
     * @param appkey          API秘钥
     * @param mchId           商户号
     * @param payNotifyUrl    支付结果通知地址
     * @param refundNotifyUrl 退款结果通知地址
     */
    public static void setWxPayConfig(String appid, String appkey, String mchId, String payNotifyUrl, String refundNotifyUrl) throws TClientException {
        WxPayConfig.setConfig(appid, appkey, mchId, payNotifyUrl, refundNotifyUrl);
    }

    /**
     * 初始化配置(带证书)
     *
     * @param appid           应用ID
     * @param appkey          API秘钥
     * @param mchId           商户号
     * @param payNotifyUrl    支付结果通知地址
     * @param refundNotifyUrl 退款结果通知地址
     * @param certPath        证书路径
     * @param certPassword    证书密码
     */
    public static void setWxPayConfig(String appid, String appkey, String mchId, String payNotifyUrl, String refundNotifyUrl, String certPath, String certPassword) throws TClientException {
        WxPayConfig.setConfig(appid, appkey, mchId, payNotifyUrl, refundNotifyUrl, certPath, certPassword);
    }

    /**
     * 支付
     *
     * @param outTradeNo  商户订单号
     * @param subject     商品标题
     * @param totalAmount 商品总金额(单位:分)
     * @param totalAmount 交易类型 扫码支付：NATIVE   H5支付：MWEB
     */
    public static Map<String, String> pay(String outTradeNo, String subject, String totalAmount) throws TClientException {
        try {
            SortedMap<String, String> req = new TreeMap();
            //应用ID
            req.put("appid", WxPayConfig.APPID);
            //商户号
            req.put("mch_id", WxPayConfig.MCHID);
            //32位随机字符串
            req.put("nonce_str", WxPayConfig.APIKEY);
            //商品描述
            req.put("body", subject);
            //商户订单号
            req.put("out_trade_no", outTradeNo);
            //标价金额(分)
            req.put("total_fee", totalAmount);
            //回调地址
            req.put("notify_url", WxPayConfig.PAY_NOTIFY_URL);
            //交易类型
            req.put("trade_type", "NATIVE");
            //签名
            req.put("sign", WXPayUtil.generateSignature(req, WxPayConfig.APIKEY, WXPayConstants.SignType.MD5));
            //参数转换
            String xmlBody = WXPayUtil.generateSignedXml(req, WxPayConfig.APIKEY);
            //请求接口
            String result = HttpUtil.doPost(WxPayConfig.PAY_URL, xmlBody);
            System.err.println(result);
            //返回 Map 类型
            return WXPayUtil.xmlToMap(result);
        } catch (Exception e) {
            throw new TClientException("微信支付失败！错误信息：" + e.getMessage());
        }
    }

    /**
     * 支付结果处理
     *
     * @param req 支付结果
     * @return
     * @throws TClientException
     */
    public static Map<String, String> payResult(String req) throws TClientException {
        try {
            return WXPayUtil.xmlToMap(req);
        } catch (Exception e) {
            throw new TClientException("微信支付返回结果解析失败！错误信息：" + e.getMessage());
        }
    }

    /**
     * 订单查询
     *
     * @param transactionId 微信订单号
     * @return
     */
    public static Map<String, String> payQuery(String transactionId) throws TClientException {
        try {
            SortedMap<String, String> req = new TreeMap();
            //应用ID
            req.put("appid", WxPayConfig.APPID);
            //商户号
            req.put("mch_id", WxPayConfig.MCHID);
            //32位随机字符串
            req.put("nonce_str", WxPayConfig.APIKEY);
            //微信订单号
            req.put("transaction_id", transactionId);
            //签名
            req.put("sign", WXPayUtil.generateSignature(req, WxPayConfig.APIKEY, WXPayConstants.SignType.MD5));
            //参数转换
            String xmlBody = WXPayUtil.generateSignedXml(req, WxPayConfig.APIKEY);
            //请求接口
            String result = HttpUtil.doPost(WxPayConfig.PAY_QUERY_URL, xmlBody);
            System.err.println(result);
            //返回 Map 类型
            return WXPayUtil.xmlToMap(result);
        } catch (Exception e) {
            throw new TClientException("微信订单查询失败！错误信息：" + e.getMessage());
        }
    }

    /**
     * 退款
     *
     * @param transactionId 微信订单号
     * @param outRefundNo   商户退款单号
     * @param totalAmount   支付总金额(单位：分)
     * @param refundAmount  退款金额(单位：分)
     * @param refundDesc    退款原因
     * @return
     * @throws TClientException
     */
    public static Map<String, String> refund(String transactionId, String outRefundNo, String totalAmount, String refundAmount, String refundDesc) throws TClientException {
        try {
            if (StringUtil.isNull(WxPayConfig.CERT_PATH) || StringUtil.isNull(WxPayConfig.CERT_PASSWORD)) {
                throw new TClientException("未配置证书，请到微信商户后台进行退款！");
            }
            SortedMap<String, String> req = new TreeMap();
            //应用ID
            req.put("appid", WxPayConfig.APPID);
            //商户号
            req.put("mch_id", WxPayConfig.MCHID);
            //32位随机字符串
            req.put("nonce_str", WxPayConfig.APIKEY);
            //微信订单号
            req.put("transaction_id", transactionId);
            //商户退款单号
            req.put("out_refund_no", outRefundNo);
            //支付总金额(单位：分)
            req.put("total_fee", totalAmount);
            //退款金额(单位：分)
            req.put("refund_fee", refundAmount);
            //退款货币种类
            req.put("refund_fee_type", "CNY");
            //退款原因
            req.put("refund_desc", refundDesc);
            //退款通知URL
            req.put("notify_url", WxPayConfig.REFUND_NOTIFY_URL);
            //签名
            req.put("sign", WXPayUtil.generateSignature(req, WxPayConfig.APIKEY, WXPayConstants.SignType.MD5));
            //参数转换
            String xmlBody = WXPayUtil.generateSignedXml(req, WxPayConfig.APIKEY);
            //请求接口
            String result = WxHttpUtil.httpPostReflect(WxPayConfig.REFUND_URL, xmlBody);
            System.err.println(result);
            //返回 Map 类型
            return WXPayUtil.xmlToMap(result);
        } catch (Exception e) {
            throw new TClientException("微信订单退款失败！错误信息：" + e.getMessage());
        }
    }

    /**
     * 退款查询
     *
     * @param refundId 微信退款单号
     * @return
     */
    public static Map<String, String> refundQuery(String refundId) throws TClientException {
        try {
            SortedMap<String, String> req = new TreeMap();
            //应用ID
            req.put("appid", WxPayConfig.APPID);
            //商户号
            req.put("mch_id", WxPayConfig.MCHID);
            //32位随机字符串
            req.put("nonce_str", WxPayConfig.APIKEY);
            //微信订单号
            req.put("refund_id", refundId);
            //签名
            req.put("sign", WXPayUtil.generateSignature(req, WxPayConfig.APIKEY, WXPayConstants.SignType.MD5));
            //参数转换
            String xmlBody = WXPayUtil.generateSignedXml(req, WxPayConfig.APIKEY);
            //请求接口
            String result = HttpUtil.doPost(WxPayConfig.REFUND_QUERY_URL, xmlBody);
            System.err.println(result);
            //返回 Map 类型
            return WXPayUtil.xmlToMap(result);
        } catch (Exception e) {
            throw new TClientException("微信订单查询失败！错误信息：" + e.getMessage());
        }
    }

    /**
     * 退款结果处理
     *
     * @param req 退款结果
     * @return
     * @throws TClientException
     */
    public static Map<String, String> refundResult(String req) throws TClientException {
        try {
            Map<String,String> rmap = WXPayUtil.xmlToMap(req);
            String result = descrypt(rmap.get("req_info"));
            return WXPayUtil.xmlToMap(result);
        } catch (Exception e) {
            throw new TClientException("微信退款返回结果解析失败！错误信息：" + e.getMessage());
        }
    }

    /**
     * 微信退款信息解密
     * @param reqInfo
     * @return
     * @throws TClientException
     */
    public static String descrypt(String reqInfo) throws TClientException {
        try {
            Base64.Decoder decoder = Base64.getDecoder();
            byte[] reqInfoB = decoder.decode(reqInfo);
            String key_ = DigestUtils.md5Hex(WxPayConfig.APIKEY).toLowerCase();

            if (Security.getProvider("BC") == null){
                Security.addProvider(new BouncyCastleProvider());
            }
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
            SecretKeySpec secretKeySpec = new SecretKeySpec(key_.getBytes(), "AES");
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
            return new String(cipher.doFinal(reqInfoB));
        }catch (Exception e){
            throw new TClientException("微信支付退款参数解密失败！错误信息："+e.getMessage());
        }
    }


}
